package com.platform.core.security.auth;

import cn.hutool.http.Header;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.platform.comm.config.properties.JwtProperties;
import com.platform.comm.dto.DtoMapper;
import com.platform.comm.jwt.JwtTokenUtil;
import com.platform.comm.util.CommonWriter;
import com.platform.comm.util.DateTimeUtil;
import com.platform.comm.util.RedisUtil;
import com.platform.comm.web.results.DataJsonResult;
import com.platform.core.service.SysUserService;
import com.platform.dto.NcloudSysOnlineUserDto;
import com.platform.uaa.service.CustomUserDetails;
import com.platform.utils.IpUtil;
import com.platform.utils.ServletUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.stream.Collectors;

import static com.platform.uaa.controller.AuthController.LOGIN_TOKEN_KEY;

/**
 * Description: 登录成功
 *
 * @author sunzhubin.zh created on 2019/9/30
 */
@Component
@Slf4j
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    private final JwtTokenUtil jwtTokenUtil;
    private final ApplicationContext applicationContext;
    private final SysUserService sysUserService;
    private final DtoMapper dtoMapper;
    private final RedisUtil redisUtil;
    private final JwtProperties jwtProperties;

    public CustomAuthenticationSuccessHandler(JwtTokenUtil jwtTokenUtil,
                                              ApplicationContext applicationContext,
                                              SysUserService sysUserService, DtoMapper dtoMapper, RedisUtil redisUtil, JwtProperties jwtProperties) {
        this.jwtTokenUtil = jwtTokenUtil;
        this.applicationContext = applicationContext;
        this.sysUserService = sysUserService;
        this.dtoMapper = dtoMapper;
        this.redisUtil = redisUtil;
        this.jwtProperties = jwtProperties;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Authentication authentication) throws IOException {
        //获得授权后可得到用户信息(非jwt 方式)
        CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();
        //将身份 存储到SecurityContext里
        SecurityContext securityContext = SecurityContextHolder.getContext();
        securityContext.setAuthentication(authentication);
        //使用jwt生成token 用于权限效验
        JwtTokenUtil.JwtUser jwtUser = dtoMapper.map(userDetails, JwtTokenUtil.JwtUser.class);
        jwtUser.setPwdExpire(DateTimeUtil.toStdLongTimeStr(userDetails.getLastPasswordReset()));
        jwtUser.setAuth(userDetails.getAuthorities()
                .parallelStream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.joining(",")));
        String token = jwtTokenUtil.generateAccessToken(jwtUser);
        TokenDto tokenDto = new TokenDto(token,
                userDetails.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()));
        // 通知用户更新
        if (jwtUser.isFirst()) {
            applicationContext.publishEvent(new LoginSuccessEvent(userDetails.getUsername(), sysUserService));
        }
        CommonWriter.write(DataJsonResult.succeed(tokenDto), response);
    }

    private void generateOnlineUserInfo(OAuth2AccessToken oAuth2AccessToken) {
        try {
            HttpServletRequest request = ServletUtils.getRequest();
            assert request != null;
            UserAgent ua = UserAgentUtil.parse(request.getHeader(Header.USER_AGENT.toString()));
            String browser = ua.getBrowser().getName();
            String platForm = ua.getPlatform().getName();
            String host = IpUtil.getIpAddr(request);
            JwtTokenUtil.JwtUser user = (JwtTokenUtil.JwtUser) oAuth2AccessToken.getAdditionalInformation().get("user");
            String jti = oAuth2AccessToken.getAdditionalInformation().get("jti").toString();
            NcloudSysOnlineUserDto onlineUserDto = NcloudSysOnlineUserDto.builder()
                    .tokenId(jti)
                    .browser(browser)
                    .os(platForm)
                    .userName(user.getRealName())
                    .departName(user.getDepartName())
                    .loginTime(LocalDateTime.now())
                    .ipaddr(host)
                    .status("在线")
                    .build();
            redisUtil.set(getTokenKey(jti), onlineUserDto, jwtProperties.getExpiration());
        } catch (Exception e) {
            log.error("在线用户信息获取失败");
        }
    }

    private String getTokenKey(String token) {
        return LOGIN_TOKEN_KEY + token;
    }
}
